package com.zj.sa_token.util.avoid;


import com.zj.sa_token.util.redis.RedisUtil;
import com.zj.sa_token.util.result.ResultUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import webgis.tools.StringFacs;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;

@Order(1)
@Aspect
@Component
@Slf4j
public class AvoidRepeatableCommitAspect {
    @Autowired
    private RedisUtil redisUtil;

    //注解类的切入点写法
    @Pointcut("@annotation(AvoidRepeatableCommit)")
    public void AvoidRepeatableCommit(){

    }

    //环绕通知 ProceedingJoinPoint 执行proceed方法的作用是让目标方法执行，这也是环绕通知和前置、后置通知方法的一个最大区别。
    // 2、简单理解，环绕通知=前置+目标方法执行+后置通知，proceed方法就是用于启动目标方法执行的
    @Around("AvoidRepeatableCommit()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        // 接收到请求   定时任务不是web请求
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String ip = IPUtil.getIP(request);
        //获取注解
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        //获取请求参数
        Map query = request.getParameterMap();
        //目标类、方法
        String className = method.getDeclaringClass().getName();
        String name = method.getName();
        String ipKey = String.format("%s#%s#%s#%s", ip, className, name, query);
        int hashCode = Math.abs(ipKey.hashCode());
        String key = String.format("%s_%d", ip, hashCode);
        log.info("ipKey={},hashCode={},key={}", ipKey, hashCode, key);
        AvoidRepeatableCommit avoidRepeatableCommit = method.getAnnotation(AvoidRepeatableCommit.class);
        long timeout = avoidRepeatableCommit.timeout();
        if (timeout < 0) {
            //默认30 秒
            timeout = 30;
        }
        String value = String.valueOf(redisUtil.get(key));
        if (!StringFacs.isEmpty(value) && !("null").equals(value)) {
            return ResultUtil.error(-1,"亲! 你点的太快了");
        }else{
            redisUtil.set(key, "-", timeout);
//            System.out.println("Around22222222");
            //执行方法*/
            return point.proceed();
        }
    }

//    @Before("@annotation(com.zj.sa_token.util.avoid.AvoidRepeatableCommit)")
//    public void beforeT(){
//        System.out.println("before1111");
//    }
//
//    //前面方法走了异步，可能不是最后执行
//    @After("@annotation(com.zj.sa_token.util.avoid.AvoidRepeatableCommit)")
//    public void afterT(JoinPoint joinPoint){
//        System.out.println("after3333");
//    }
}
